package ar.uade.fain.ai.tpo.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import ar.uade.fain.ai.tpo.dao.db.ConnectionPool;

public class DAOSupport {
	
	private static DAOSupport instancia;
	
	public DAOSupport() {
		super();
	}
	
	public static DAOSupport get() {
		if (instancia == null) {
			instancia = new DAOSupport();
		}
		return instancia;
	}

	public <T> List<T> select(
			final String sentencia, 
			final ParameterSetter parameterSetter,
			final ResultSetExtractor<T> extractor) {
		Connection conn = getConnection();
		List<T> resultados = null;
		PreparedStatement statement = null;
		ResultSet rs = null;
		try {
			statement = conn.prepareStatement(sentencia);
			parameterSetter.setParametros(statement);
			rs = statement.executeQuery();
			resultados = extractor.extraer(rs);
			rs.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		} finally {
			if (rs != null){
				try{
					rs.close();
				}catch(Exception e){}
			}
			if(statement != null){
				try{
					statement.close();
				}
				catch(Exception e){}
			}
			ConnectionPool.getInstancia().release(conn);
		}
		return resultados;
	}

	private Connection getConnection() {
		Connection conn = ConnectionPool.getInstancia().getConnection();
		if (conn == null) {
			return null;
		}
		return conn;
	}

	public <T> List<T> select(
			final String sentencia, 
			final ParameterSetter parameterSetter,
			final RowMapper<T> mapper) {
		return select(sentencia, 
				parameterSetter,
				new ResultSetExtractorAdapter<T>(mapper));
	}

	public <T> List<T> select(
			final String sentencia, 
			final RowMapper<T> mapper) {
		return select(sentencia, 
				ParameterSetter.VACIO,
				new ResultSetExtractorAdapter<T>(mapper));
	}

	public <T> List<T> select(
			final String sentencia,
			final Long id,
			final ResultSetExtractor<T> extractor) {
		return select(sentencia, 
				ParameterSetter.Factory.idOnly(id),
				extractor);
	}
	
	public <T> List<T> select(
			final String sentencia,
			final Long id,
			final RowMapper<T> mapper) {
		return select(sentencia, 
				ParameterSetter.Factory.idOnly(id),
				new ResultSetExtractorAdapter<T>(mapper));
	}
	
	public Long selectNextId(final String sentencia) {
		return select(sentencia, 
				ParameterSetter.VACIO,
				RowMapper.ID_MAPPER)
				.get(0);
	}
	
	public boolean update(
			final String sentencia, 
			final ParameterSetter parameterSetter) {
		int matches = 0;
		Connection conn = getConnection();
		PreparedStatement statement = null;
		try {
			statement = conn.prepareStatement(sentencia);
			parameterSetter.setParametros(statement);
			matches = statement.executeUpdate();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		} finally {
			if (statement != null){
				try{
					statement.close();
				}catch(Exception e) {
				}
			}
			ConnectionPool.getInstancia().release(conn);
		}
		return matches > 0;
	}

	public boolean execute(
			final String sentencia, 
			final ParameterSetter parameterSetter) {
		boolean match = false;
		PreparedStatement statement = null;
		Connection conn = getConnection();
		try {
			statement = conn.prepareStatement(sentencia);
			parameterSetter.setParametros(statement);
			match = statement.executeUpdate() > 0;
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		} finally {
			if (statement != null){
				try{
					statement.close();
				}catch(Exception e) {
				}
			}
			ConnectionPool.getInstancia().release(conn);
		}
		return match;
	}

	public boolean insert(
			final String sentencia, 
			final ParameterSetter parameterSetter) {
		return execute(sentencia, parameterSetter);
	}

	public boolean delete(
			final String sentencia, 
			final ParameterSetter parameterSetter) {
		return execute(sentencia, parameterSetter);
	}

}
